/**
 * 给定字符串，再给定Q个询问：L R s
 * 问[L, R]区间内子序列为s的一共有多少个
 * s的长度保证为3
 * 
 * 首先分块
 * 令Single[c][i]第i块中字符c的数量
 * 令Double[a][b][i]表示第i块中序列ab的数量
 * 令Triple[a][b][c][i]表示第i块中序列abc的数量
 * 
 * 注意i放在后面，因为在calcMid中可以使用高维数组访问的常数优化
 * 同时由于只统计块内，可以全部使用int
 * 
 * 对于一次查询(s, e, T)，一般而言分为三段：
 * 1. [s...R[Block[s]]]，即s到本块的右边界，暴力统计出 pre_a,pre_ab,pre_abc
 * 2. [Block[s] + 1, Block[e] - 1], 即中间整块的区域，根据预处理数据暴力统计出 mid_a,mid_b,mid_c,mid_ab,mid_bc,mid_abc
 * 3. [L[Block[e]]...e], 即e所在块的最边界到e的区域，暴力统计出 suf_c, suf_bc, suf_abc
 * 
 * 另外注意到N在8E4，询问则有5E5，因此s和e恰好落在块边界的机会很大，可以省掉段1或者段3。
 * 加了这个优化从1902ms降到1488ms。
 * 
 * 根据以上统计即可计算出当前答案
 * 时间复杂度为O(26^2*N + Q*sqrt(N))
 * 需要做常数优化
 */
#include <bits/stdc++.h>
using namespace std;

char *__abc147, *__xyz258, __ma369[1000000];
#define __hv007() ((__abc147==__xyz258) && (__xyz258=(__abc147=__ma369)+fread(__ma369,1,100000,stdin),__abc147==__xyz258) ? EOF : *__abc147++)

int getUnsigned(){
	int sgn = 1;
	char ch = __hv007();
	while('0' > ch or ch > '9') ch = -__hv007();
 
	int ret = (int)(ch-'0');
	while( '0' <= (ch=__hv007()) && ch <= '9' ) ret = ret * 10 + (int)(ch-'0');
	return ret;
}

int getString(char s[]){
    char * p = s;
    char ch = __hv007();
    while('a' > ch or ch > 'z') ch = __hv007();
    
    *p++ = ch;
    while('a' <= (ch = __hv007()) and ch <= 'z') *p++ = ch;
    return p - s;    
}

char __pq981[1000000];
char const * const __rs721 = __pq981 + 1000000;
char * __qw752 = __pq981;

#define __ge(c) (__qw752 == __rs721 ? fwrite(__pq981, 1, 1000000, stdout), __qw752 = __pq981 + 1, *__pq981 = (c) : *__qw752++ = (c))

void putChar(char c){__ge(c);}

void putULL(long long x){
    if(x == 0) return (void)(__ge('0'));

    char st[25];
	int top = 0;
	while(x){
		st[top++] = x % 10 + '0';
		x /= 10;
	} 
	while(top) __ge(st[--top]);
	return;
}

void finish(){
	fwrite(__pq981, 1, __qw752 - __pq981, stdout);
}

using llt = long long;

#ifndef ONLINE_JUDGE
int const SZ = 12;
int const BLOCK_CNT_LIMIT = 12;
int const ONE_BLOCK_SZ = 12;
#else
int const SZ = 8E4 + 10;
int const BLOCK_CNT_LIMIT = 300;
int const ONE_BLOCK_SZ = 300;
#endif

using array_t = int [BLOCK_CNT_LIMIT];

int N;
int Q;
char S[SZ];
int BlockSize;
int BlockCnt;
int Block[SZ];

int Left[BLOCK_CNT_LIMIT], Right[BLOCK_CNT_LIMIT];

/// Single[c][i] 表示第i块中字符c的数量
array_t Single[27];
/// Double[a][b][i] 表示第i块中序列ab的数量
array_t Double[27][27];
/// Triple[a][b][c][i] 表示第i块中序列abc的数量
array_t Triple[27][27][27];
/// Cnt[i][c]表示S[1...i]中字符c的数量
int Cnt[SZ][27];

void init(){
    BlockSize = sqrt(N) + 1;
    // BlockSize = 12;
    BlockCnt = N / BlockSize;
    if(N % BlockSize) ++BlockCnt;

    int p = 1;
    for(int i=1;i<=BlockCnt;++i){
        fill(Block + (Left[i] = p), Block + (Right[i] = min(p + BlockSize - 1, N)) + 1, i);
        for(;p<=Right[i];++p){
            int c = S[p] - 'a' + 1;
            copy(Cnt[p - 1], Cnt[p - 1] + 27, Cnt[p]);
            ++Cnt[p][c];

            for(int b=1;b<=26;++b){
                for(int a=1;a<=26;++a){
                    Triple[b][a][c][i] += Double[b][a][i];
                }
                Double[b][c][i] += Single[b][i];
            }
            ++Single[c][i];
        }

        // for(int a=1;a<=26;++a)for(int b=1;b<=26;++b)for(int c=1;c<=26;++c){
        //     D[i][a][b][c] = D[i - 1][a][b][c] + Triple[i][a][b][c];
        // }
    }    

    // for(int i=1;i<=BlockCnt;++i){
    //     cout << i << ": [" << Left[i] << ", " << Right[i] << "]" << endl;
    //     for(int a=1;a<=26;++a){
    //         if(Single[i][a]){
    //             cout << (char)(a + 'a' - 1) << ": " << Single[i][a] << endl;
    //         }
    //         for(int b=1;b<=26;++b){
    //             if(Double[i][a][b]){
    //                 cout << (char)(a + 'a' - 1) << (char)(b + 'a' - 1) << ": " << Double[i][a][b] << endl;
    //             }
    //             for(int c=1;c<=26;++c){
    //                 if(Triple[i][a][b][c]){
    //                     cout << (char)(a + 'a' - 1) << (char)(b + 'a' - 1)  << (char)(c + 'a' - 1) << ": " << Triple[i][a][b][c] << endl;
    //                 }
    //             }
    //         }
    //     }
    // }

    // for(int i=1;i<=BlockCnt;++i){
    //     cout << i << ": [" << Left[i] << ", " << Right[i] << "]" << endl;
    //     for(int a=1;a<=26;++a){
    //         for(int b=1;b<=26;++b){
    //             for(int c=1;c<=26;++c){
    //                 if(D[i][a][b][c]){
    //                     cout << (char)(a + 'a' - 1) << (char)(b + 'a' - 1)  << (char)(c + 'a' - 1) << ": " << D[i][a][b][c] << endl;
    //                 }
    //             }
    //         }
    //     }
    // }

    return;
}

int L, R;
char T[5];

void calcPre(int s, int e, int & pre_a, int & pre_ab, int & pre_abc){
    pre_a = pre_ab = pre_abc = 0;
    if(s > e) return;

    int c = T[2] - 'a' + 1;    
    pre_a = 0;
    int suf = Cnt[e][c] - Cnt[s - 1][c];
    if(S[s] == T[0]) pre_a = 1;
    if(S[s] == T[2]) --suf;

    for(int i=s+1;i<=e;++i){
        if(S[i] == T[2]){
            --suf;
        }
        if(S[i] == T[1]){
            pre_abc += pre_a * suf;
            pre_ab += pre_a;
        }
        if(S[i] == T[0]){
            ++pre_a;
        }
    }    

    return;
}

void calcSuf(int s, int e, int & suf_c, int & suf_bc, int & suf_abc){
    suf_c = suf_bc = suf_abc = 0;
    if(s > e) return;

    int a = T[0] - 'a' + 1;
    suf_c = 0;
    int pre = Cnt[e][a] - Cnt[s - 1][a];
    if(S[e] == T[2]) suf_c = 1;
    if(S[e] == T[0]) --pre;

    for(int i=e-1;i>=s;--i){
        if(S[i] == T[0]){
            --pre;
        }
        if(S[i] == T[1]){
            suf_abc += suf_c * pre;
            suf_bc += suf_c;
        }
        if(S[i] == T[2]){
            ++suf_c;
        }
    }

    return;
}

void calcMid(int s, int e, int & mid_a, int & mid_b, int & mid_c, llt & mid_ab, llt & mid_bc, llt & mid_abc){
    mid_a = mid_b = mid_c = mid_ab = mid_bc = mid_abc = 0;
    if(s > e) return;

    int a = T[0] - 'a' + 1;
    int b = T[1] - 'a' + 1;
    int c = T[2] - 'a' + 1;

    const auto & sa = Single[a];
    const auto & sb = Single[b];
    const auto & sc = Single[c];
    const auto & dab = Double[a][b];
    const auto & dbc = Double[b][c];
    const auto & tabc = Triple[a][b][c];

    for(int i=s;i<=e;++i){
        mid_abc += (llt)mid_a * dbc[i] + mid_ab * sc[i] + tabc[i];

        mid_ab += (llt)mid_a * sb[i] + dab[i];
        mid_bc += (llt)mid_b * sc[i] + dbc[i];

        mid_a += sa[i];
        mid_b += sb[i];
        mid_c += sc[i];        
    }

    return;
}

llt proc(){
    int bs = Block[L], be = Block[R];

    if(bs == be){
        int pre_a, pre_ab, pre_abc;
        if(L == Left[bs] and R == Right[bs]) return Triple[T[0]-'a'+1][T[1]-'a'+1][T[2]-'a'+1][bs];

        calcPre(L, R, pre_a, pre_ab, pre_abc);
        return pre_abc;
    }

    int pre_a, pre_ab, pre_abc;
    if(L != Left[bs]){
        calcPre(L, Right[bs], pre_a, pre_ab, pre_abc);
    }else{
        pre_a = pre_ab = pre_abc = 0;
    }
    

    int suf_c, suf_bc, suf_abc;
    if(R != Right[be]){
        calcSuf(Left[be], R, suf_c, suf_bc, suf_abc);
    }else{
        suf_c = suf_bc = suf_abc = 0;
    }
    

    int mid_a, mid_b, mid_c;
    llt mid_ab, mid_bc, mid_abc;
    calcMid(bs + (L != Left[bs] ? 1 : 0), be - (R != Right[be] ? 1 : 0), mid_a, mid_b, mid_c, mid_ab, mid_bc, mid_abc);

    llt ans = mid_abc + pre_abc + suf_abc;
    ans += pre_a * (mid_bc + suf_bc);
    ans += pre_ab * (mid_c + suf_c + 0LL);
    ans += (llt)mid_a * suf_bc;
    ans += mid_ab * suf_c;
    ans += (llt)pre_a * mid_b * suf_c;
    return ans;
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("z.txt", "r", stdin);
#endif
    // ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    N = getUnsigned();
    Q = getUnsigned();
    getString(S + 1);
    init();
    while(Q--){
        L = getUnsigned();
        R = getUnsigned();
        getString(T);
        putULL(proc());
        putChar('\n');
    }

    finish();
    return 0;
}